#!/usr/bin/env python3
"""
RedFire 架构验证脚本
====================

验证重构后的架构是否符合设计原则：
1. 依赖倒置原则 - 业务层只依赖接口
2. 单一职责原则 - 每个模块职责清晰
3. 开闭原则 - 对扩展开放，对修改关闭
4. 接口隔离原则 - 接口设计合理
5. 依赖注入原则 - 依赖通过容器注入
"""

import ast
import sys
import logging
from pathlib import Path
from typing import Dict, List, Set, Tuple, Any
from dataclasses import dataclass
from enum import Enum

# 添加项目根目录到路径
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class ViolationType(Enum):
    """违规类型"""
    WRONG_DEPENDENCY = "wrong_dependency"  # 错误的依赖方向
    CONCRETE_DEPENDENCY = "concrete_dependency"  # 依赖具体实现
    CIRCULAR_DEPENDENCY = "circular_dependency"  # 循环依赖
    LAYER_VIOLATION = "layer_violation"  # 层级违规
    MISSING_INTERFACE = "missing_interface"  # 缺少接口抽象


@dataclass
class ArchitectureViolation:
    """架构违规"""
    file_path: Path
    line_number: int
    violation_type: ViolationType
    description: str
    suggestion: str
    severity: str = "warning"  # error, warning, info


class ArchitectureValidator:
    """架构验证器"""
    
    def __init__(self, project_root: Path):
        self.project_root = project_root
        self.violations: List[ArchitectureViolation] = []
        
        # 定义架构规则
        self.setup_architecture_rules()
    
    def setup_architecture_rules(self):
        """设置架构规则"""
        
        # 允许的依赖关系 (from -> to)
        self.allowed_dependencies = {
            # 业务层可以依赖的模块
            "backend/services": [
                "shared/contracts",  # ✅ 只依赖接口
                "shared/models",     # ✅ 数据传输对象
                "shared/exceptions", # ✅ 通用异常
                "backend/shared/containers",  # ✅ 依赖注入容器
            ],
            
            # 仓库层可以依赖的模块
            "backend/services/*/repositories": [
                "shared/contracts",  # ✅ 数据库接口
                "shared/models",     # ✅ 数据模型
                "shared/exceptions", # ✅ 异常处理
            ],
            
            # API层可以依赖的模块
            "backend/services/*/api": [
                "shared/models",     # ✅ 请求/响应模型
                "shared/exceptions", # ✅ 异常处理
                "backend/services/*/services",  # ✅ 业务服务
                "backend/services/*/containers", # ✅ DI容器
            ],
            
            # 实现层可以依赖的模块
            "backend/shared/implementations": [
                "shared/contracts",  # ✅ 实现接口
                "shared/exceptions", # ✅ 异常处理
            ],
            
            # 容器层可以依赖的模块
            "backend/shared/containers": [
                "shared/contracts",  # ✅ 接口定义
                "backend/shared/implementations", # ✅ 具体实现
                "backend/shared/config",         # ✅ 配置管理
            ]
        }
        
        # 禁止的依赖关系
        self.forbidden_dependencies = {
            # 业务层不能直接依赖具体实现
            "backend/services": [
                "shared/data/database",  # ❌ 不能直接依赖数据库实现
                "shared/data/cache",     # ❌ 不能直接依赖缓存实现
                "shared/security",       # ❌ 不能直接依赖安全实现
                "backend/shared/implementations", # ❌ 不能直接依赖具体实现
            ],
            
            # 接口层不能依赖实现
            "shared/contracts": [
                "backend/shared/implementations", # ❌ 接口不能依赖实现
                "shared/data",                   # ❌ 接口不能依赖数据层
            ],
            
            # 模型层不能依赖业务逻辑
            "shared/models": [
                "backend/services",              # ❌ 模型不能依赖业务逻辑
                "backend/shared/implementations", # ❌ 模型不能依赖实现
            ]
        }
        
        # 必须使用接口的场景
        self.interface_requirements = {
            "database_access": "shared.contracts.database.DatabaseInterface",
            "cache_access": "shared.contracts.cache.CacheInterface", 
            "auth_service": "shared.contracts.auth.AuthInterface",
            "storage_service": "shared.contracts.storage.StorageInterface",
        }
    
    def validate_project(self) -> bool:
        """验证整个项目"""
        logger.info("🔍 开始架构验证...")
        
        # 验证服务层
        self.validate_services()
        
        # 验证依赖关系
        self.validate_dependencies()
        
        # 验证接口使用
        self.validate_interface_usage()
        
        # 验证循环依赖
        self.validate_circular_dependencies()
        
        # 生成报告
        return self.generate_report()
    
    def validate_services(self):
        """验证服务层架构"""
        logger.info("📋 验证服务层架构...")
        
        services_dir = self.project_root / "backend" / "services"
        if not services_dir.exists():
            return
        
        for service_dir in services_dir.iterdir():
            if service_dir.is_dir() and not service_dir.name.startswith('.'):
                self.validate_service_structure(service_dir)
    
    def validate_service_structure(self, service_dir: Path):
        """验证单个服务的结构"""
        service_name = service_dir.name
        logger.debug(f"🔍 验证服务结构: {service_name}")
        
        # 检查必需的目录结构
        required_dirs = ["api", "services", "repositories"]
        for dir_name in required_dirs:
            dir_path = service_dir / dir_name
            if not dir_path.exists():
                self.violations.append(ArchitectureViolation(
                    file_path=service_dir,
                    line_number=0,
                    violation_type=ViolationType.LAYER_VIOLATION,
                    description=f"服务 {service_name} 缺少必需目录: {dir_name}",
                    suggestion=f"创建目录 {dir_path} 并按照分层架构组织代码",
                    severity="warning"
                ))
        
        # 验证各层的依赖关系
        self.validate_service_dependencies(service_dir)
    
    def validate_service_dependencies(self, service_dir: Path):
        """验证服务内部依赖关系"""
        
        # 获取所有Python文件
        python_files = list(service_dir.rglob("*.py"))
        
        for py_file in python_files:
            if py_file.name == "__init__.py":
                continue
            
            try:
                self.validate_file_dependencies(py_file)
            except Exception as e:
                logger.warning(f"⚠️ 解析文件失败: {py_file} - {e}")
    
    def validate_file_dependencies(self, file_path: Path):
        """验证单个文件的依赖关系"""
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            # 解析AST
            tree = ast.parse(content, filename=str(file_path))
            
            # 提取导入语句
            imports = self.extract_imports(tree)
            
            # 验证每个导入
            for import_info in imports:
                self.validate_import(file_path, import_info)
                
        except Exception as e:
            logger.debug(f"解析文件异常: {file_path} - {e}")
    
    def extract_imports(self, tree: ast.AST) -> List[Dict[str, Any]]:
        """提取导入语句"""
        imports = []
        
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    imports.append({
                        'type': 'import',
                        'module': alias.name,
                        'alias': alias.asname,
                        'line': node.lineno
                    })
            
            elif isinstance(node, ast.ImportFrom):
                if node.module:
                    imports.append({
                        'type': 'from_import',
                        'module': node.module,
                        'names': [alias.name for alias in node.names],
                        'line': node.lineno
                    })
        
        return imports
    
    def validate_import(self, file_path: Path, import_info: Dict[str, Any]):
        """验证单个导入语句"""
        module = import_info['module']
        line_number = import_info['line']
        
        # 获取文件的相对路径
        rel_path = file_path.relative_to(self.project_root)
        
        # 检查是否违反依赖规则
        self.check_dependency_violations(rel_path, module, line_number)
        
        # 检查是否应该使用接口
        self.check_interface_requirements(rel_path, module, line_number)
    
    def check_dependency_violations(self, file_path: Path, module: str, line_number: int):
        """检查依赖违规"""
        
        # 确定文件所属的层级
        file_layer = self.get_file_layer(file_path)
        
        if not file_layer:
            return
        
        # 检查禁止的依赖
        forbidden = self.forbidden_dependencies.get(file_layer, [])
        for forbidden_pattern in forbidden:
            if module.startswith(forbidden_pattern):
                self.violations.append(ArchitectureViolation(
                    file_path=file_path,
                    line_number=line_number,
                    violation_type=ViolationType.WRONG_DEPENDENCY,
                    description=f"违反依赖倒置原则: {file_layer} 不应该依赖 {module}",
                    suggestion=f"使用 shared/contracts 中的接口替代具体实现",
                    severity="error"
                ))
        
        # 检查是否依赖了具体实现
        if self.is_concrete_implementation(module):
            if not self.is_allowed_concrete_dependency(file_layer, module):
                self.violations.append(ArchitectureViolation(
                    file_path=file_path,
                    line_number=line_number,
                    violation_type=ViolationType.CONCRETE_DEPENDENCY,
                    description=f"直接依赖具体实现: {module}",
                    suggestion="通过依赖注入容器获取实例，而不是直接导入",
                    severity="warning"
                ))
    
    def check_interface_requirements(self, file_path: Path, module: str, line_number: int):
        """检查接口使用要求"""
        
        # 检查数据库访问
        if any(keyword in module for keyword in ['database', 'mysql', 'postgres', 'sqlite']):
            if 'shared.contracts.database' not in module:
                self.violations.append(ArchitectureViolation(
                    file_path=file_path,
                    line_number=line_number,
                    violation_type=ViolationType.MISSING_INTERFACE,
                    description=f"数据库访问应该使用接口: {module}",
                    suggestion="使用 shared.contracts.database.DatabaseInterface",
                    severity="warning"
                ))
        
        # 检查缓存访问
        if any(keyword in module for keyword in ['cache', 'redis', 'memcached']):
            if 'shared.contracts.cache' not in module:
                self.violations.append(ArchitectureViolation(
                    file_path=file_path,
                    line_number=line_number,
                    violation_type=ViolationType.MISSING_INTERFACE,
                    description=f"缓存访问应该使用接口: {module}",
                    suggestion="使用 shared.contracts.cache.CacheInterface",
                    severity="warning"
                ))
    
    def get_file_layer(self, file_path: Path) -> str:
        """确定文件所属的架构层级"""
        path_str = str(file_path)
        
        if "backend/services" in path_str and "/api/" in path_str:
            return "backend/services/*/api"
        elif "backend/services" in path_str and "/services/" in path_str:
            return "backend/services"
        elif "backend/services" in path_str and "/repositories/" in path_str:
            return "backend/services/*/repositories"
        elif "backend/shared/implementations" in path_str:
            return "backend/shared/implementations"
        elif "backend/shared/containers" in path_str:
            return "backend/shared/containers"
        elif "shared/contracts" in path_str:
            return "shared/contracts"
        elif "shared/models" in path_str:
            return "shared/models"
        
        return ""
    
    def is_concrete_implementation(self, module: str) -> bool:
        """判断是否为具体实现"""
        concrete_patterns = [
            "shared.data.database.managers",
            "shared.data.cache",
            "shared.security.authentication.unified_auth",
            "backend.shared.implementations"
        ]
        
        return any(pattern in module for pattern in concrete_patterns)
    
    def is_allowed_concrete_dependency(self, file_layer: str, module: str) -> bool:
        """判断是否允许依赖具体实现"""
        
        # 容器层可以依赖具体实现
        if file_layer == "backend/shared/containers":
            return True
        
        # 工厂层可以依赖具体实现
        if "factory" in file_layer.lower():
            return True
        
        return False
    
    def validate_dependencies(self):
        """验证依赖关系"""
        logger.info("🔗 验证依赖关系...")
        # 这里可以添加更复杂的依赖关系验证逻辑
    
    def validate_interface_usage(self):
        """验证接口使用"""
        logger.info("🎯 验证接口使用...")
        # 这里可以添加接口使用验证逻辑
    
    def validate_circular_dependencies(self):
        """验证循环依赖"""
        logger.info("🔄 验证循环依赖...")
        # 这里可以添加循环依赖检测逻辑
    
    def generate_report(self) -> bool:
        """生成验证报告"""
        logger.info("📊 生成验证报告...")
        
        # 统计违规情况
        error_count = sum(1 for v in self.violations if v.severity == "error")
        warning_count = sum(1 for v in self.violations if v.severity == "warning")
        info_count = sum(1 for v in self.violations if v.severity == "info")
        
        print("\n" + "="*80)
        print("🏗️  RedFire 架构验证报告")
        print("="*80)
        
        if not self.violations:
            print("🎉 恭喜！架构验证通过，没有发现违规问题！")
            print("\n✅ 架构设计符合以下原则:")
            print("   • 依赖倒置原则 - 业务层只依赖接口")
            print("   • 单一职责原则 - 每个模块职责清晰")
            print("   • 开闭原则 - 对扩展开放，对修改关闭")
            print("   • 接口隔离原则 - 接口设计合理")
            print("   • 依赖注入原则 - 依赖通过容器注入")
            return True
        
        print(f"📋 发现 {len(self.violations)} 个问题:")
        print(f"   🔴 错误: {error_count}")
        print(f"   🟡 警告: {warning_count}")  
        print(f"   🔵 信息: {info_count}")
        print()
        
        # 按严重程度分组显示
        for severity in ["error", "warning", "info"]:
            severity_violations = [v for v in self.violations if v.severity == severity]
            if not severity_violations:
                continue
            
            severity_icon = {"error": "🔴", "warning": "🟡", "info": "🔵"}[severity]
            print(f"{severity_icon} {severity.upper()} ({len(severity_violations)} 个):")
            print("-" * 60)
            
            for violation in severity_violations:
                print(f"📁 {violation.file_path}:{violation.line_number}")
                print(f"   问题: {violation.description}")
                print(f"   建议: {violation.suggestion}")
                print()
        
        print("="*80)
        
        # 提供改进建议
        self.print_improvement_suggestions()
        
        return error_count == 0
    
    def print_improvement_suggestions(self):
        """打印改进建议"""
        print("💡 架构改进建议:")
        print("-" * 40)
        
        suggestions = [
            "1. 将业务逻辑从具体实现中解耦，使用接口抽象",
            "2. 通过依赖注入容器管理服务实例",
            "3. 确保数据访问层只使用 DatabaseInterface",
            "4. 缓存操作只使用 CacheInterface",
            "5. 认证服务只使用 AuthInterface",
            "6. 避免跨层级的直接依赖",
            "7. 使用工厂模式创建具体实现",
            "8. 保持接口的稳定性和向后兼容性"
        ]
        
        for suggestion in suggestions:
            print(f"   {suggestion}")
        
        print("\n📚 相关文档:")
        print("   • 架构设计文档: docs/architecture.md")
        print("   • 依赖注入指南: docs/dependency-injection.md")
        print("   • 最佳实践: docs/best-practices.md")


def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description='RedFire 架构验证工具')
    parser.add_argument('--project-root', type=Path, default=PROJECT_ROOT, help='项目根目录')
    parser.add_argument('--verbose', '-v', action='store_true', help='详细输出')
    
    args = parser.parse_args()
    
    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    
    # 创建验证器
    validator = ArchitectureValidator(args.project_root)
    
    # 执行验证
    success = validator.validate_project()
    
    # 根据结果退出
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()
